#include <string>
#include <cstring>
#include <cmath>
#include <ctime>
#include <fstream>
#include <iostream>
#include <sstream>
#include <sys/time.h>

using namespace std;

namespace MetricSpaceBenchmark::MLIndex::LIMS {

// 指定存储的数据点数量
#define NUUM 10000000

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    // 指针数组 loc, 用于存储 NUUM 个浮动指针, 每个指针指向一个浮动类型数组
    float *loc[NUUM];

    int pnum, num, PairA = 0; // pnum : 簇或枢轴点的数量; PairA:数据对数

    // ptype : 距离计算函数的类型
    int ptype = 2;    // 默认是欧式距离
    // 存储距离计算的最大值
    double mm;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    // 计算两个点 i 和 j 之间的距离
    double dis(int i, int j, int dim) {
        // 欧几里得距离, 计算方式为每个维度的差的平方和的平方根
        if (ptype == 2) {
            double sum = 0;
            for (int k = 0; k < dim; k++) {
                sum += pow(loc[i][k] - loc[j][k], 2);
            }
            return pow(sum, 0.5);
        }

        // 曼哈顿距离, 即每个维度的差的绝对值之和
        if (ptype == 1) {
            double sum = 0;
            for (int k = 0; k < dim; k++) sum += fabs(loc[i][k] - loc[j][k]);
            return sum;
        }

        // L5 距离, 计算每个维度差的 5 次方和的 1/5 次方
        if (ptype == 5) {
            double sum = 0;
            for (int k = 0; k < dim; k++) sum += pow(loc[i][k] - loc[j][k], 5);
            return pow(sum, 0.2);
        }

        // 切比雪夫距离, 计算每个维度差的绝对值的最大值
        if (ptype == 0) {
            double max = 0, p;
            for (int k = 0; k < dim; k++) {
                p = abs(loc[i][k] - loc[j][k]);
                if (p > max) max = p;
            }
            return max;
        }
    }
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /*
     * 读取文件: re-read the file
     * @ filename: 文件名
     * @ dim: 数据的维度
     * @ type: 文件的类型，决定如何读取数据
     */
    void readm(const string &filename, int dim, int type) {

        ifstream readFile;
        readFile.open(filename, ifstream::in);

        num = 2000000;    // 读取的数量，默认200百万
        ptype = 2;
        PairA = 100000;

        // 为每个数据点分配内存
        for (int i = 0; i < num; i++)
            loc[i] = new float[dim + 3];

        string line;  // 用于存储每行读取的文本
        int i = 0;    // 计数器

        // type == 1, load each cluster data file
        if (type) {
            // 逐行读取文件内容.
            // 每行数据通过 stringstream 分割,并通过 atof() 将字符串转换为浮动数值,存储在 loc[i][j] 中
            while (getline(readFile, line)) {
                stringstream ss(line);
                string value;
                int j = 0;
                // pass the id of each point
                getline(ss, value, ',');
                while (getline(ss, value, ',')) {
                    loc[i][j] = atof(value.c_str());
                    ++j;
                }
                ++i;
            }
        } else {
            // type == 0, load whole data file
            while (getline(readFile, line)) {
                stringstream ss(line);
                string value;
                int j = 0;
                while (getline(ss, value, ',')) {
                    loc[i][j] = atof(value.c_str());
                    ++j;
                }
                ++i;
            }
        }
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
        num = i;   // 记录真实的数据点数
        readFile.close();

        int j = 1;
        mm = 0;
        double mm1 = 0;
        // 计算与第一个数据点距离最远的点 j, 然后再计算这个点与其他点的最大距离 mm
        for (int i = 1; i < num; i++)
            if (dis(0, i, dim) > mm1) {
                j = i;
                mm1 = dis(0, i, dim); // mm1 距离loc[0]最远的点
            }
        for (int i = 1; i < num; i++)
            if (dis(j, i, dim) > mm)
                mm = dis(j, i, dim); // mm 距离loc[j]最远的点
    }
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
}